﻿#include "ff.h"
#include "ebook_api.h"
#include "ebook_init.h"
#include "ebook_util.h"
#include "db_format.h"
#if LV_HOR_RES_MAX==240 && LV_VER_RES_MAX==320
const int EBOOK_VERSION = ((1)<<17) + (0);
    #define LINES_PER_PAGE	14
    #define CHARS_PER_LINE	28
#elif LV_HOR_RES_MAX==128 && LV_VER_RES_MAX==160
const int EBOOK_VERSION = ((1)<<18) + (0);
    #define LINES_PER_PAGE	9
    #define CHARS_PER_LINE	18	//22*7=154 < 160
#elif LV_HOR_RES_MAX==240 && LV_VER_RES_MAX==240
const int EBOOK_VERSION = ((1)<<19) + (0);
    #define LINES_PER_PAGE	10
    #define CHARS_PER_LINE	28
#else
    #error "ebook width and height not defined!"
#endif

#define is_english(c) (((c)>='a'&&(c)<='z')||((c)>='A'&&(c)<='Z'))
#define BE2LE(a)	((((a)>>8)&0xff)+(((a)&0xff)<<8))

int is_blank_line(unsigned char * txt, int len)
{
	if(len == 0)
	{
		assert(0);
	}
	else if(len == 1)
	{
		return txt[0] == '\n';
	}
	else if(len == 2)
	{
		return txt[0] == '\r' && txt[1] == '\n';
	}
	else
	{
		assert(txt[0] != '\n');
		assert(!(txt[0] == '\r' && txt[1] == '\n'));
	}
	
	return 0;
}

int ansi_get_word(unsigned char * txt, int start, int end, int*used)//返回used是消耗掉buff的长度，函数返回值显示时候的占位符长度
{
	if(is_english(txt[start]))
	{
		int i=start+1;
		for(i=start+1; i<end; i++)
		{
			if(!is_english(txt[i]))
				break;
		}
		*used = i-start;
		return i-start;
	}
	if(txt[start] < 0x80)
	{
		*used = 1;
		return 1;
	}
	else
	{
		*used = 2;
		return 2;
	}
}

int ansi_one_line(unsigned char * txt, int start, int end)//返回一行的长度
{
	int show_len = 0;
	int used = 0;
	int line=0;
	int i=0;

	for(i=start; i<end && line<CHARS_PER_LINE; )
	{
		if(txt[i] == '\n')
		{
			i += 1;
			break;
		}
		else if(txt[i] == '\r')
		{
			i += 1;
		}
		else
		{
			show_len = ansi_get_word(txt, i, end, &used);

			if(line+show_len > CHARS_PER_LINE)
			{
				if(i==start)
				{
					i = start + CHARS_PER_LINE;
				}
				break;
			}
			else
			{
				line += show_len;
				i += used;
			}
		}
	}
	return i-start;
}

int ansi_page_len(unsigned char * txt, int len)
{
	//整屏可显示14行，每行28个英文字符，单词不可以回行。
	int row = 0;
	int i = 0;
	while(i<len)
	{
		int ret = ansi_one_line(txt, i, len);
		if(ret == -1)
		{
			return -1;
		}
		else if(is_blank_line(&txt[i], ret))
		{
			i += ret;
		}
		else
		{
			i += ret;
			row++;
			if(row >= LINES_PER_PAGE)
			{
				return i;
			}
		}
	}
	return len;
}

int utf8_get_word(unsigned char * txt, int start, int end, int*used)//返回used是消耗掉buff的长度，函数返回值显示时候的占位符长度
{
	if(is_english(txt[start]))
	{
		int i=start+1;
		for(i=start+1; i<end; i++)
		{
			if(!is_english(txt[i]))
				break;
		}
		*used = i-start;
		return i-start;
	}
	if(txt[start] < 0x80)
	{
		*used = 1;
		return 1;
	}
	else if((txt[start] & 0xC0) == 0x80)//	10xxxxxx
	{
		assert(0);
		*used = 1;
		return 2;
	}
	else if((txt[start] & 0xE0) == 0xC0)//	110xxxxx 10xxxxxx
	{
		*used = 2;
		return 2;
	}
	else if((txt[start] & 0xF0) == 0xE0)//	1110xxxx 10xxxxxx 10xxxxxx
	{
		*used = 3;
		return 2;
	}
	else if((txt[start] & 0xF8) == 0xF0)//	11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
	{
		*used = 4;
		return 2;
	}
	else if((txt[start] & 0xFC) == 0xF8)//	111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
	{
		*used = 5;
		return 2;
	}
	else if((txt[start] & 0xFC) == 0xF8)//	1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
	{
		*used = 6;
		return 2;
	}
	else
	{
		assert(0);
		*used = 1;
		return 2;
	}
}

int utf8_one_line(unsigned char * txt, int start, int end)//返回一行的长度
{
	int show_len = 0;
	int used = 0;
	int line=0;
	int i=0;

	for(i=start; i<end && line<CHARS_PER_LINE; )
	{
		if(txt[i] == '\n')
		{
			i += 1;
			break;
		}
		else if(txt[i] == '\r')
		{
			i += 1;
		}
		else
		{
			show_len = utf8_get_word(txt, i, end, &used);

			if(line+show_len > CHARS_PER_LINE)
			{
				if(i==start)
				{
					i = start + CHARS_PER_LINE;
				}
				break;
			}
			else
			{
				line += show_len;
				i += used;
			}
		}
	}
	return i-start;
}

int utf8_page_len(unsigned char * txt, int len)
{
	//整屏可显示14行，每行28个英文字符，单词不可以回行。
	int row = 0;
	int i = 0;
	while(i<len)
	{
		int ret = utf8_one_line(txt, i, len);
		if(ret == -1)
		{
			return -1;
		}
		else if(is_blank_line(&txt[i], ret))
		{
			i += ret;
		}
		else
		{
			i += ret;
			row++;
			if(row >= LINES_PER_PAGE)
			{
				return i;
			}
		}
	}
	return len;
}

int utf16le_get_word(unsigned short * p, int start, int end, int*used)//返回used是消耗掉buff的长度，函数返回值显示时候的占位符长度
{
	if(is_english(p[start]))
	{
		int i=start+1;
		for(i=start+1; i<end; i++)
		{
			if(!is_english(p[i]))
				break;
		}
		*used = i-start;
		return i-start;
	}
	if(p[start] < 0x0080)
	{
		*used = 1;
		return 1;
	}
	else
	{
		*used = 1;
		return 2;
	}
}

int utf16le_one_line(unsigned short * txt, int start, int end)//返回一行的长度
{
	int show_len = 0;
	int used = 0;
	int line = 0;
	int i = 0;
	
	for(i=start; i<end && line<CHARS_PER_LINE; )
	{
		if(txt[i] == 0x000A)
		{
			i += 1;
			break;
		}
		else if(txt[i] == 0x000D)
		{
			i += 1;
		}
		else
		{
			show_len = utf16le_get_word(txt, i, end, &used);

			if(line+show_len > CHARS_PER_LINE)
			{
				if(i==start)
				{
					i = start + CHARS_PER_LINE;
				}
				break;
			}
			else
			{
				line += show_len;
				i += used;
			}
		}
	}
	return i-start;
}

int is_blank_line16(unsigned short* txt, int len)
{
	if(len == 0)
	{
		assert(0);
	}
	else if(len == 1)
	{
		return txt[0] == 0x000A;
	}
	else if(len == 2)
	{
		return txt[0] == 0x000D && txt[1] == 0x000A;
	}
	else
	{
		assert(txt[0] != 0x000A);
		assert(!(txt[0] == 0x000D && txt[1] == 0x000A));
	}
	
	return 0;
}

int utf16le_page_len(unsigned short * txt, int len)
{
	//整屏可显示14行，每行28个英文字符，单词不可以回行。
	int row = 0;
	int i = 0;
	while(i<len)
	{
		int ret = utf16le_one_line(txt, i, len);
		if(ret == -1)
		{
			return -1;
		}
		else if(is_blank_line16(&txt[i], ret))
		{
			i += ret;
		}
		else
		{
			i += ret;
			row++;
			if(row >= LINES_PER_PAGE)
			{
				return i;
			}
		}
	}
	return len;
}

int utf16be_get_word(unsigned short * p, int start, int end, int*used)//返回used是消耗掉buff的长度，函数返回值显示时候的占位符长度
{
	unsigned short tmp = BE2LE(p[start]);
	if(is_english(tmp))
	{
		int i=start+1;
		for(i=start+1; i<end; i++)
		{
			unsigned short tmp = BE2LE(p[i]);
			if(!is_english(tmp))
				break;
		}
		*used = i-start;
		return i-start;
	}
	if(tmp < 0x0080)
	{
		*used = 1;
		return 1;
	}
	else
	{
		*used = 1;
		return 2;
	}
}

int utf16be_one_line(unsigned short * txt, int start, int end)//返回一行的长度
{
	int show_len = 0;
	int used = 0;
	int line = 0;
	int i = 0;

	for(i=start; i<end && line<CHARS_PER_LINE; )
	{
		if(BE2LE(txt[i]) == 0x000A)
		{
			i += 1;
			break;
		}
		else if(BE2LE(txt[i]) == 0x000D)
		{
			i += 1;
		}
		else
		{
			show_len = utf16be_get_word(txt, i, end, &used);

			if(line+show_len > CHARS_PER_LINE)
			{
				if(i==start)
				{
					i = start + CHARS_PER_LINE;
				}
				break;
			}
			else
			{
				line += show_len;
				i += used;
			}
		}
	}
	return i-start;
}

int is_blank_line16A(unsigned short* txt, int len)
{
	if(len == 0)
	{
		assert(0);
	}
	else if(len == 1)
	{
		return txt[0] == 0x0A00;
	}
	else if(len == 2)
	{
		return txt[0] == 0x0D00 && txt[1] == 0x0A00;
	}
	else
	{
		assert(txt[0] != 0x0A00);
		assert(!(txt[0] == 0x0D00 && txt[1] == 0x0A00));
	}
	
	return 0;
}

int utf16be_page_len(unsigned short * txt, int len)
{
	//整屏可显示14行，每行28个英文字符，单词不可以回行。
	int row = 0;
	int i = 0;
	while(i<len)
	{
		int ret = utf16be_one_line(txt, i, len);
		if(ret == -1)
		{
			return -1;
		}
		else if(is_blank_line16A(&txt[i], ret))
		{
			i += ret;
		}
		else
		{
			i += ret;
			row++;
			if(row >= LINES_PER_PAGE)
			{
				return i;
			}
		}
	}
	return len;
}

int calculate_page_len(unsigned char * txt, int len)
{
	switch(hebook->format)
	{
	case ASCII_FORMAT:
	case ANSI_FORMAT:
		return ansi_page_len(txt, len);
	case UTF_8_NOBOM_FORMAT:
	case UTF_8_BOM_FORMAT:
		return utf8_page_len(txt, len);
	case UTF_16_L_ENDIAN_FORMAT:
		return utf16le_page_len((unsigned short*)txt, len/2) * 2;
	case UTF_16_B_ENDIAN_FORMAT:
		return utf16be_page_len((unsigned short*)txt, len/2) * 2;
	case UTF_32_L_ENDIAN_FORMAT:
	case UTF_32_B_ENDIAN_FORMAT:
		return -1;
	default:
		return -1;
	}
}

int get_txt_info(void)
{
	//获取txt文件信息，编码格式、文件大小等
	int res;
	unsigned int br;
	hebook->f_size = (int)f_size(hebook->f_txt);
	f_lseek(hebook->f_txt, 0);
	res = f_read(hebook->f_txt, &hebook->txt_ui, TXT_SIZE, &br);
	if(res == FR_OK)
	{
		hebook->format = db_check_format(hebook->txt_ui, br, hebook->default_format);
		if(ERROR_FORMAT == hebook->format)
		{
			return -1;
		}
	}
	return 0;
}

int calculate_page_offset(int offset[2])
{
	//return 0:		构建索引文件单步OK
	//return -1:	构建索引文件出错
	//return -2:	txt文件结束，本次单步无数据

	int res;
	unsigned br = 0;
	int page_len;

	f_lseek(hebook->f_txt, offset[0]); 
	res = f_read(hebook->f_txt, hebook->txt_index, TXT_SIZE, &br);
	if(res != FR_OK)
	{
		return -1;
	}
	if(br == 0)
	{
		return -2;
	}

	page_len = calculate_page_len(hebook->txt_index, br);
	if(page_len == -1)
	{
		return -1;
	}

	offset[1] = offset[0] + page_len;

	return 0;
}

int save_index(int offset[2])
{
	int res;
	unsigned br = 0;
	long long last = sizeof(INDEX_HEAD) + hebook->pages*sizeof(int);
	f_lseek(hebook->f_idx, last); 
	res = f_write(hebook->f_idx, offset, sizeof(int)*2, &br);
	if(res == FR_OK && br == sizeof(int)*2)
	{
		hebook->pages++;
		return res;
	}
	else
	{
		return -1;
	}
}

int convert_page_to_ui(unsigned char * from, unsigned char * to)
{
	//整屏可显示14行，每行28个英文字符，单词不可以回行。
	char tmp[64];
	int len = strlen((char*)from);
	int i = 0;
	to[0] = 0;

	while(i<len)
	{
		int ret = utf8_one_line(from, i, len);
		if(ret == -1)
		{
			return -1;
		}
		else if(is_blank_line(&from[i], ret))
		{
			i += ret;
		}
		else
		{
			memcpy(tmp, &from[i], ret);
			tmp[ret] = 0;
			strcat((char*)to, tmp);
			if(tmp[ret-1] != '\n')
			{
				strcat((char*)to, "\r\n");
			}
			i+=ret;
		}
	}
	return 0;
}

int convert_page(int len)
{
	switch(hebook->format)
	{
	case ASCII_FORMAT:
	case ANSI_FORMAT:
		{
			int ret = db_gb2312_to_utf8(hebook->txt_ui, len, hebook->convert_txt, TXT_SIZE);
			hebook->convert_txt[ret] = 0;
			if(ret == 0)
			{
				return -1;
			}
		}
		break;

	case UTF_8_NOBOM_FORMAT:
	case UTF_8_BOM_FORMAT:
		strcpy((char*)hebook->convert_txt, (char*)hebook->txt_ui);
		break;

	case UTF_16_L_ENDIAN_FORMAT:
		{
			int ret = UTF_16LE_to_utf8(hebook->txt_ui, len, hebook->convert_txt, TXT_SIZE);
			hebook->convert_txt[ret] = 0;
			if(ret == 0)
			{
				return -1;
			}
		}
		break;

	case UTF_16_B_ENDIAN_FORMAT:
		{
			int ret = UTF_16BE_to_utf8(hebook->txt_ui, len, hebook->convert_txt, TXT_SIZE);
			hebook->convert_txt[ret] = 0;
			if(ret == 0)
			{
				return -1;
			}
		}
		break;

	case UTF_32_L_ENDIAN_FORMAT:
	case UTF_32_B_ENDIAN_FORMAT:
		return -1;

	default:
		return -1;
	}

	return convert_page_to_ui(hebook->convert_txt, hebook->utf8_txt);
}

int get_page_(void)
{
	int res;
	unsigned br = 0;
	int offset[2];
	long long last;
	int len;

	last = sizeof(INDEX_HEAD) + hebook->page*sizeof(int);
	f_lseek(hebook->f_idx, last); 
	res = f_read(hebook->f_idx, offset, sizeof(offset), &br);
	if(res != FR_OK)
	{
		return -1;
	}
	if(br != sizeof(offset))
	{
		return -1;
	}

	len = offset[1] - offset[0];
	if(len >= TXT_SIZE)
	{
		return -1;
	}

	f_lseek(hebook->f_txt, offset[0]); 
	res = f_read(hebook->f_txt, hebook->txt_ui, len, &br);
	if(res != FR_OK)
	{
		return -1;
	}
	if((int)br != len)
	{
		return -1;
	}

	hebook->txt_ui[len] = 0;

	return len;
}

int get_page(void)
{
	int res;

	if(hebook->building)
	{
		//assert(hebook->q_to_task != 0);
		//assert(hebook->q_fm_task != 0);
		//assert(hebook->task != 0);
		int msg = hebook->page;
		res = OAL_queue_send(&hebook->q_to_task, &msg, OAL_WAIT_FOREVER);
		if(res == OAL_SUCCESS)
		{
			res = OAL_queue_recv(&hebook->q_fm_task, &msg, OAL_WAIT_FOREVER);
			if(res == OAL_SUCCESS)
			{
				if(msg == -1)
				{
					return -1;
				}
				else
				{
					//assert(msg == hebook->page);
					return convert_page(msg);
				}
			}
			else
			{
				return -1;
			}
		}
		else
		{
			return -1;
		}
	}
	else
	{
		res = get_page_();
		if(res == -1)
		{
			return res;
		}
		return convert_page(res);
	}
}

int get_last_offset(void)
{
	int res;
	unsigned br = 0;
	int offset;
	long long last = f_size(hebook->f_idx) - sizeof(int);
	//assert(sizeof(INDEX_HEAD) + head.pages*sizeof(int) == last);

	f_lseek(hebook->f_idx, last);
	res = f_read(hebook->f_idx, &offset, sizeof(int), &br);
	if(res != FR_OK)
	{
		return -1;
	}
	if(br != sizeof(int))
	{
		return -1;
	}
	return offset;
}

void* task_build_index(void* prm)
{
	int offset[2] = {0,0};
	prm=prm;

	offset[0] = get_last_offset();

	if(offset[0] == -1)
	{
		hebook->building = -1;
		hebook->cb(-1);
	}

    for(;;)
	{
		int msg;
		if(OAL_SUCCESS == OAL_queue_recv(&hebook->q_to_task, &msg, 0))
		{
			if(msg == -1)
			{
				break;
			}
			else
			{
				int send = get_page_();
				OAL_queue_send(&hebook->q_fm_task, &send, OAL_WAIT_FOREVER);
				//assert(OAL_SUCCESS == res);
			}
		}
		else
		{
			if(hebook->building == 1)
			{
				int res = calculate_page_offset(offset);
				switch(res)
				{
				case 0:	//构建索引文件单步OK，保存index信息
					res = save_index(offset);
					offset[0] = offset[1];
					if(res == FR_OK)
					{
						hebook->cb(hebook->pages);
					}
					else
					{
						hebook->building = -1;
						hebook->cb(-1);
					}
					break;
				case -1:	//构建索引文件出错，不保存index信息
					hebook->building = -1;
					hebook->cb(-1);
					break;
				case -2:	//txt文件结束，本次单步无数据，不保存index信息
					hebook->building = 0;
					hebook->cb(-2);
					break;
				default:
					assert(0);	//not arrived
					break;
				}
			}
			OAL_sleep(10);
		}
    }
    return 0;
}

int create_task(void)
{
	int res;
	OAL_QUEUE_POOL pool = {sizeof(int) * 1};
	res = OAL_queue_create(&hebook->q_to_task, (char*)"to task", sizeof(int), &pool);
	if(res != OAL_SUCCESS)
	{
		hebook->q_to_task = (void*)0;
		return -1;
	}
	res = OAL_queue_create(&hebook->q_fm_task, (char*)"from task", sizeof(int), &pool);
	if(res != OAL_SUCCESS)
	{
		res = OAL_queue_delete(&hebook->q_to_task);
		hebook->q_to_task = (void*)0;
		hebook->q_fm_task = (void*)0;
		return -1;
	}

	hebook->task = OAL_thread_create(task_build_index, 0, (char *)"build index", OAL_THREAD_PRIORITY_LOW, 512);
	if(hebook->task == 0)
	{
		res = OAL_queue_delete(&hebook->q_to_task);
		res = OAL_queue_delete(&hebook->q_fm_task);
		hebook->q_to_task = (void*)0;
		hebook->q_fm_task = (void*)0;
		return -1;
	}
	
	return 0;
}

int close_task(void)
{
	int msg = -1;
    OAL_queue_send(&hebook->q_to_task, &msg, OAL_WAIT_FOREVER);
    OAL_thread_join(hebook->task);
	hebook->task = (void*)0;
	OAL_queue_delete(&hebook->q_to_task);
	OAL_queue_delete(&hebook->q_fm_task);
	hebook->q_to_task = (void*)0;
	hebook->q_fm_task = (void*)0;
	return 0;
}

int fnamecmp(char * path1, char * path2)
{
	char * p1 = path1 + strlen(path1) - 5;
	char * p2 = path2 + strlen(path2) - 5;

	while(p1 > path1)
	{
		char c = *(p1-1);
		if(c == '/' || c == '\\') break;
		else --p1;
	}
	while(p2 > path2)
	{
		char c = *(p2-1);
		if(c == '/' || c == '\\') break;
		else --p2;
	}
	return strcmp(p1, p2);
}


FRESULT ffopen(FIL ** fp, const char* path, unsigned char mode)
{
	FRESULT res;

	assert(*fp == 0);
	*fp = (FIL*)OAL_calloc(1, sizeof(FIL));
	if(0==*fp)
	{
		return FR_INT_ERR;
	}
	
	res = f_open(*fp, path, mode);

	if(FR_OK != res)
	{
		OAL_free(*fp);
		*fp = 0;
	}

	return res;
}

FRESULT ffclose(FIL ** fp)
{
	if(*fp)
	{
		FRESULT res = f_close(*fp);
		OAL_free(*fp); 
		*fp = 0;
		return res;
	}
	return FR_OK;
}
